package io.bdmc.modules.api.service;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import javax.annotation.PostConstruct;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson2.JSONObject;

import io.bdmc.common.utils.R;
import io.bdmc.config.MqttConfig;
import io.bdmc.modules.bss.entity.DeviceDevice;
import io.bdmc.modules.bss.service.IDeviceDeviceService;
import lombok.extern.slf4j.Slf4j;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.bdmc.modules.bss.entity.*;
import io.bdmc.modules.bss.model.DeviceAlarmParam;
import io.bdmc.modules.bss.service.*;

@Service
@Slf4j
public class MqttService {

    @Autowired
    private MqttConfig mqttConfig;

    @Autowired
    private MqttConnectOptions mqttConnectOptions;

    @Autowired
    IDeviceDeviceService _devSvs;

    private MqttClient client;

    @Autowired
    IFibreFibreService _fibreSvs;

    @Autowired
    IFibreCablePointService _pointSvs;

    @Autowired
    IDeviceEquipmentroomService _roomSvs;

    @Autowired
    IDeviceFrameService _frameSvs;

    @Autowired
    IDeviceAlarmService _alarmSvs;

    @Autowired
    IDeviceAlarmRealtimeService _alarmRealSvs;

    @Autowired
    IDeviceFibreRealtimeService _dfrSvs;

    @Autowired
    IDeviceFibreMatchService _dfmSvs;
    @Autowired
    IDeviceMeasureService _measureSvs;

    @Autowired
    IDeviceMeasureEventService _eventService;

    @Autowired
    IDeviceRouteGroupService _routeGroupService;

    @Autowired
    IDeviceRouteService _routeService;

    @Autowired
    IDeviceRouteConfigService _routeConfigService;

    @Autowired
    IDeviceRouteAlarmSettingService _routeAlarmSettingService;

    @Autowired
    IDeviceLinkService _linkService;

    @Autowired
    IDeviceLinkGroupService _linkGroupService;

    @Autowired
    DeviceStatusService deviceStatusService;

    @PostConstruct
    private void init() {
        // 初始化时建立连接
        try {
            client = new MqttClient(mqttConfig.getHost(), mqttConfig.getClientId());
            client.connect(mqttConnectOptions);
            subscribe(mqttConfig.getServerTopic());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 订阅服务端mqtt通道
    public void subscribe(String topic) throws Exception {
        client.subscribe(topic, mqttConfig.getQos(), (topic1, message) -> {
            String payload = new String(message.getPayload());
            System.out.println("Received message: " + payload);

            // 解析消息类型
            JSONObject obj = JSONObject.parseObject(payload);
            if (!obj.containsKey("msgType"))
                return;
            String msgType = obj.getString("msgType");
            R result;

            switch (msgType) {
                case "equipmentroom":// 机房信息同步
                    List<DeviceEquipmentroom> roomList = _roomSvs.list();
                    for (DeviceEquipmentroom room : roomList) {
                        room.setFrameList(
                                _frameSvs.list(new QueryWrapper<DeviceFrame>().eq("equipmentroom_id",
                                        room.getEquipmentroomId())));
                    }
                    result = R.ok().putData(roomList);
                    break;
                case "fibre":// 光缆信息同步
                    List<FibreFibre> fibreList = _fibreSvs.list();
                    for (FibreFibre fibreFibre : fibreList) {
                        fibreFibre.setFibreCablePointList(
                                _pointSvs.list(
                                        new QueryWrapper<FibreCablePoint>().eq("fibre_id", fibreFibre.getFibreId())));
                    }
                    result = R.ok().putData(fibreList);
                    break;
                case "device":// 设备信息同步
                    List<DeviceDevice> list = _devSvs.listAllDevices();
                    result = R.ok().putData(list);
                    break;
                case "alarmRealtime":// 实时告警
                    List<DeviceAlarmRealtime> alarmRealtimeList = _alarmRealSvs.selectRealtimeAlarmList();
                    result = R.ok().putData(alarmRealtimeList);
                    break;
                case "alarmHistory":// 历史告警
                    if (!obj.containsKey("startTime") && !obj.containsKey("endTime")) {
                        result = R.error("startTime和endTime是必传参数");
                        break;
                    }
                    String startTime = obj.getString("startTime");
                    String endTime = obj.getString("endTime");
                    DeviceAlarmParam param = new DeviceAlarmParam();
                    param.setStartTime(startTime);
                    param.setEndTime(endTime);
                    List<DeviceAlarmRealtime> alarmHistoryList = _alarmSvs.selectHistoryAlarmList(param);
                    result = R.ok().putData(alarmHistoryList);
                    break;
                case "deviceFibreMatch":// 设备绑定光缆纤芯信息
                    List<DeviceFibreMatch> matchList = _dfmSvs
                            .list(new QueryWrapper<DeviceFibreMatch>().isNotNull("device_sn"));
                    result = R.ok().putData(matchList);
                    break;
                case "fibreLengthSync":// 光缆测量长度与衰耗信息
                    if (!obj.containsKey("ipaddr")) {
                        result = R.error("ipaddr是必传参数");
                        break;
                    }
                    String ipaddr = obj.getString("ipaddr");
                    QueryWrapper<DeviceFibreRealtime> w1 = new QueryWrapper<>();
                    w1.eq("ip_addr", ipaddr);
                    List<DeviceFibreRealtime> dfr = _dfrSvs.list(w1);
                    result = R.ok().putData(dfr);
                    break;
                case "deviceMeasure":// 光缆测量长度与衰耗信息
                    if (!obj.containsKey("deviceSn")) {
                        result = R.error("deviceSn是必传参数");
                        break;
                    }
                    if (!obj.containsKey("channel")) {
                        result = R.error("channel是必传参数");
                        break;
                    }
                    String sn = obj.getString("deviceSn");
                    Integer ch = obj.getInteger("channel");
                    QueryWrapper<DeviceMeasure> mw = new QueryWrapper<>();
                    mw.eq("device_sn", sn).eq("channel", ch).orderByDesc("measure_id").last(" limit 1");
                    DeviceMeasure measure = _measureSvs.getOne(mw);
                    result = R.ok().putData(measure);
                    break;
                case "routeView":// 路由试图同步接口
                    List<DeviceRouteGroup> routeGroupList = _routeGroupService.list();
                    for (DeviceRouteGroup deviceRouteGroup : routeGroupList) {
                        final List<DeviceRoute> deviceRouteList = _routeService
                                .list(new QueryWrapper<DeviceRoute>().eq("group_id",
                                        deviceRouteGroup.getRouteGroupId()));
                        for (DeviceRoute route : deviceRouteList) {
                            route.setDeviceRouteConfigList(_routeConfigService.selectByRouteId(route.getRouteId()));
                            route.setDeviceRouteAlarmSettingList(
                                    _routeAlarmSettingService.selectByRouteId(route.getRouteId()));
                        }
                        deviceRouteGroup.setDeviceRouteList(deviceRouteList);
                    }
                    result = R.ok().putData(routeGroupList);
                    break;
                case "linkView":// 链路视图同步接口
                    final List<DeviceLinkGroup> linkGroupList = _linkGroupService.list();
                    for (DeviceLinkGroup deviceLinkGroup : linkGroupList) {
                        final List<DeviceLink> deviceLinkList = _linkService
                                .list(new QueryWrapper<DeviceLink>().eq("group_id", deviceLinkGroup.getLinkGroupId()));
                        deviceLinkGroup.setDeviceLinkList(deviceLinkList);
                    }
                    result = R.ok().putData(linkGroupList);
                    break;
                case "deviceStatus":// 设备实时状态
                    if (!obj.containsKey("deviceSn")) {
                        result = R.error("deviceSn是必传参数");
                        break;
                    }
                    String deviceSn = obj.getString("deviceSn");
                    DeviceDevice dd = _devSvs.getDeviceBySn(deviceSn);
                    if (dd == null) {
                        result = R.error("设备不存在或已移除");
                        break;
                    }
                    Map<String, Object> deviceStatus = deviceStatusService.getDeviceStatus(dd);
                    result = R.ok().putData(deviceStatus);
                    break;
                default:
                    result = R.error("msgType无法识别");
                    break;
            }
            result.put("msgType", msgType);

            publish(mqttConfig.getClientTopic(), JSONObject.toJSONString(result));
        });
    }

    public void publish(String topic, String payload) {
        MqttClient publishClient;
        try {
            publishClient = new MqttClient(mqttConfig.getHost(), MqttClient.generateClientId());
            publishClient.connect(mqttConnectOptions);
            publishClient.publish(topic, payload.getBytes("utf-8"), mqttConfig.getQos(), false);
            publishClient.disconnect();
        } catch (MqttException e) {
            log.error("publish-mqtt:MqttException", e.getCause() + "," + e.getReasonCode());
            e.printStackTrace();
        } catch (UnsupportedEncodingException ue) {
            log.error("publish-mqtt:UnsupportedEncodingException", ue.getCause() + "," + ue.getMessage());
            ue.printStackTrace();
        }
    }
}
